home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1997 February / EnigmA AMIGA RUN 15 (1997)(G.R. Edizioni)(IT)[!][issue 1997-02][PLANET CD V].iso / enigma / earcd / sviluppo / svilupp2 / gmsppr10.lha / AllocateColors.c next >
C/C++ Source or Header  |  1996-10-08  |  8KB  |  300 lines

  1. #ifndef INTUITION_SCREENS_H
  2. #include <intuition/screens.h>
  3. #endif
  4.  
  5. #include <proto/graphics.h>
  6.  
  7. #include "Global.h"
  8.  
  9. /****** gamesupport.library/GS_AllocateColors ****************************
  10. *
  11. *   NAME
  12. *    GS_AllocateColors -- allocate colors in a screen.
  13. *
  14. *   SYNOPSIS
  15. *    Success = GS_AllocateColors(Screen, Colors, Distinct)
  16. *      d0                          a0       a1       d0
  17. *
  18. *    ULONG GS_AllocateColors(struct Screen *,struct GS_ColorDef *,ULONG);
  19. *
  20. *   FUNCTION
  21. *    Allocate the shared pens required for your program. You pass in
  22. *    a table of RGB values, and you get a table of pens to use.
  23. *    GS_AllocateColors() attempts to optimize the color search; so the
  24. *    result is different from that of a normal for-loop.
  25. *    We must call GS_FreeColors() when we're done with the pens.
  26. *
  27. *   INPUTS
  28. *    Screen     - the screen we want to open on
  29. *    Colors     - the Red, Green and Blue fields must be set by you; they
  30. *                 will remain unchanged.
  31. *    Distinct   - how many distinct colors to get at most. Pass 0 for
  32. *                 no limit.
  33. *
  34. *   RESULT
  35. *    Success - TRUE if everything went okay. Colors->DistinctColors
  36. *              will be filled in for you.
  37. *              If FALSE, you can check IoErr(): it returns 0 if we were
  38. *              unable to allocate some or all pens.
  39. *
  40. *    NOTE
  41. *    The algorithm has been taken from Xmris 4.02.
  42. *
  43. *   SEE ALSO
  44. *    graphics.library/ObtainBestPen(), GameSupport.h, GS_FreeColors()
  45. *
  46. *************************************************************************/
  47.  
  48. /* AFAIK, X uses 16 bit per gun */
  49. #define RGB2X(r, g, b) (((LONG)(b) - (LONG)(r)) * (56756 / 2) / 65536)
  50. #define RGB2Y(r, g, b) (((LONG)(g) - ((LONG)(r) + (LONG)(b)) / 2) / 2)
  51. #define RGB2H(r, g, b) (((LONG)(g) * 4 + (LONG)(r) * 3 + (LONG)(b)) / 8)
  52.  
  53. SAVEDS_ASM_D0A0A1(ULONG,LibGS_AllocateColors,ULONG,Distinct,struct Screen *,Screen,struct GS_ColorDef *,Colors)
  54.  
  55. {
  56.   struct ColorData
  57.     {
  58.       LONG Coord[2];            /* position in colorspace */
  59.       ULONG Distance;            /* distance to nearest allocated color */
  60.       ULONG PrivatePen;            /* Color number inside PrivateColorMap */
  61.     };
  62.  
  63.   struct ColorData *ColorData;
  64.   ULONG ColorCount;
  65.  
  66.   ColorCount=Colors->ColorCount;
  67.   Colors->DistinctColors=0;
  68.   if ((ColorData=GS_MemoryAlloc(ColorCount*sizeof(*ColorData))))
  69.     {
  70.       struct ColorMap *PrivateColorMap;
  71.  
  72.       if (!Distinct)
  73.     {
  74.       Distinct=~0;
  75.     }
  76.       PrivateColorMap=NULL;
  77.       if (Distinct>=ColorCount || (PrivateColorMap=GetColorMap(Distinct)))
  78.     {
  79.       struct ColorMap *ColorMap;        /* the ColorMap to operate on */
  80.       ULONG LastAllocated;            /* the most recently allocated color */
  81.       struct TagItem TagList[2];
  82.  
  83.       TagList[0].ti_Tag=OBP_Precision;
  84.       TagList[0].ti_Data=PRECISION_EXACT;
  85.       TagList[1].ti_Tag=TAG_DONE;
  86.  
  87.       ColorMap=Screen->ViewPort.ColorMap;
  88.  
  89.       /* init stuff */
  90.       {
  91.         ULONG i;
  92.  
  93.         for (i=0; i<ColorCount; i++)
  94.           {
  95.         Colors->Colors[i].Pen=-1L;
  96.  
  97.         ColorData[i].Coord[0] = RGB2X(Colors->Colors[i].Red>>16, Colors->Colors[i].Green>>16, Colors->Colors[i].Blue>>16);
  98.         ColorData[i].Coord[1] = RGB2Y(Colors->Colors[i].Red>>16, Colors->Colors[i].Green>>16, Colors->Colors[i].Blue>>16);
  99.         ColorData[i].Coord[2] = RGB2H(Colors->Colors[i].Red>>16, Colors->Colors[i].Green>>16, Colors->Colors[i].Blue>>16);
  100.         ColorData[i].Distance=~0;
  101.         ColorData[i].PrivatePen=~0;
  102.           }
  103.       }
  104.  
  105.       /* find & allocate "black" */
  106.       {
  107.         ULONG Black;
  108.         ULONG i;
  109.  
  110.         Black=0;
  111.         for (i=0; i<ColorCount; i++)
  112.           {
  113.         if (ColorData[i].Coord[2]<ColorData[Black].Coord[2])
  114.           {
  115.             Black=i;
  116.           }
  117.           }
  118.         Colors->Colors[Black].Pen=ObtainBestPenA(ColorMap,
  119.                              Colors->Colors[Black].Red,
  120.                              Colors->Colors[Black].Green,
  121.                              Colors->Colors[Black].Blue,
  122.                              TagList);
  123.         Colors->DistinctColors=(Colors->Colors[Black].Pen!=-1L);
  124.         Distinct--;
  125.         LastAllocated=Black;
  126.       }
  127.  
  128.       /* allocate colors in optimum order */
  129.       {
  130.         ULONG i;
  131.  
  132.         for (i=1; Colors->DistinctColors>0 && i<ColorCount; i++)    /* we've already allocated one color */
  133.           {
  134.         ULONG FarthestColor;
  135.  
  136.         /* adjust distances */
  137.         /* find farthest color */
  138.         {
  139.           ULONG j;
  140.           ULONG FarthestDistance;
  141.  
  142.           FarthestDistance=0;
  143.           for (j=0; j<ColorCount; j++)
  144.             {
  145.               if (Colors->Colors[j].Pen==-1L)
  146.             {
  147.               ULONG Distance;
  148.               int k;
  149.  
  150.               Distance=0;
  151.               for (k=3; k--;)
  152.                 {
  153.                   ULONG Delta;
  154.  
  155.                   if (ColorData[LastAllocated].Coord[k]<ColorData[j].Coord[k])
  156.                 {
  157.                   Delta=ColorData[j].Coord[k]-ColorData[LastAllocated].Coord[k];
  158.                 }
  159.                   else
  160.                 {
  161.                   Delta=ColorData[LastAllocated].Coord[k]-ColorData[j].Coord[k];
  162.                 }
  163.                   Distance+=(Delta*Delta)/4;
  164.                 }
  165.               if (Distance<ColorData[j].Distance)
  166.                 {
  167.                   ColorData[j].Distance=Distance;
  168.                 }
  169.               if (ColorData[j].Distance>=FarthestDistance)
  170.                 {
  171.                   FarthestDistance=ColorData[j].Distance;
  172.                   FarthestColor=j;
  173.                 }
  174.             }
  175.             }
  176.         }
  177.  
  178.         /* allocate farthest color */
  179.         if (Distinct)
  180.           {
  181.             Colors->Colors[FarthestColor].Pen=ObtainBestPenA(ColorMap,
  182.                                      Colors->Colors[FarthestColor].Red,
  183.                                      Colors->Colors[FarthestColor].Green,
  184.                                      Colors->Colors[FarthestColor].Blue,
  185.                                      TagList);
  186.           }
  187.         else
  188.           {
  189.             ULONG Color;
  190.             ULONG j;
  191.  
  192.             assert(PrivateColorMap);
  193.             Color=FindColor(PrivateColorMap,
  194.                     Colors->Colors[FarthestColor].Red,
  195.                     Colors->Colors[FarthestColor].Green,
  196.                     Colors->Colors[FarthestColor].Blue,
  197.                     -1);
  198.             for (j=0; ColorData[j].PrivatePen!=Color; j++)
  199.               ;
  200.             assert(Colors->Colors[j].Pen!=-1);
  201.             Colors->Colors[FarthestColor].Pen=ObtainPen(ColorMap,Colors->Colors[j].Pen,0,0,0,PEN_NO_SETCOLOR);
  202.           }
  203.         if (Colors->Colors[FarthestColor].Pen==-1L)
  204.           {
  205.             Colors->DistinctColors=0;
  206.           }
  207.         else if (Distinct)
  208.           {
  209.             LONG j;
  210.             int ReallyDistinct;
  211.  
  212.             ReallyDistinct=TRUE;
  213.             for (j=0; ReallyDistinct && j<ColorCount; j++)
  214.               {
  215.             if (j!=FarthestColor && Colors->Colors[j].Pen==Colors->Colors[FarthestColor].Pen)
  216.               {
  217.                 ReallyDistinct=FALSE;
  218.               }
  219.               }
  220.             if (ReallyDistinct)
  221.               {
  222.             Colors->DistinctColors++;
  223.             Distinct--;
  224.             if (PrivateColorMap)
  225.               {
  226.                 struct
  227.                   {
  228.                 ULONG Red, Green, Blue;
  229.                   } Color;
  230.  
  231.                 GetRGB32(ColorMap,Colors->Colors[FarthestColor].Pen,1,&Color.Red);
  232.                 SetRGB32CM(PrivateColorMap,Distinct,Color.Red,Color.Green,Color.Blue);
  233.                 ColorData[FarthestColor].PrivatePen=Distinct;
  234.               }
  235.               }
  236.           }
  237.         LastAllocated=FarthestColor;
  238.           }
  239.       }
  240.       FreeColorMap(PrivateColorMap);
  241.     }
  242.       /* clean up */
  243.       GS_MemoryFree(ColorData);
  244.       if (Colors->DistinctColors==0)
  245.     {
  246.       GS_FreeColors(Screen,Colors);
  247.     }
  248.     }
  249.   return Colors->DistinctColors;
  250. }
  251.  
  252. /****** gamesupport.library/GS_FreeColors ********************************
  253. *
  254. *   NAME
  255. *    GS_FreeColors -- free pens after we've used them.
  256. *
  257. *   SYNOPSIS
  258. *    GS_FreeColors(Screen, Colors)
  259. *                    a0      a1
  260. *
  261. *    void GS_FreeColors(struct Screen *, struct GS_ColorDef *);
  262. *
  263. *   FUNCTION
  264. *    Free the pens allocated by GS_AllocateColors(). Make sure there's
  265. *    no visible graphics with those pens still on the screen; the
  266. *    usual thing is to close the window, then call GS_FreeColors(),
  267. *    then unlock the screen.
  268. *    You can call GS_FreeColors() as often as you want. You must not
  269. *    call GS_FreeColors() on an array that had no GS_AllocateColors()
  270. *    called on it.
  271. *
  272. *   INPUTS
  273. *    Screen     - the screen. Must be the same screen as used for
  274. *                 GS_AllocateColors(), of course.
  275. *    Colors     - the structure filled in by GS_AllocateColors()
  276. *
  277. *   SEE ALSO
  278. *    GS_AllocateColors(), graphics.library/ReleasePen()
  279. *
  280. *************************************************************************/
  281.  
  282. SAVEDS_ASM_A0A1(void,LibGS_FreeColors,struct Screen *,Screen,struct GS_ColorDef *,Colors)
  283.  
  284. {
  285.   struct ColorMap *ColorMap;
  286.   ULONG ColorCount;
  287.   struct GS_Color *Color;
  288.  
  289.   ColorCount=Colors->ColorCount;
  290.   ColorMap=Screen->ViewPort.ColorMap;
  291.   Color=Colors->Colors;
  292.   while (ColorCount)
  293.     {
  294.       ReleasePen(ColorMap,Color->Pen);
  295.       Color->Pen=-1L;
  296.       Color++;
  297.       ColorCount--;
  298.     }
  299. }
  300.